#include <stdio.h>
#include <string.h>
#include <pcre.h>

#define MAX_COMMAND_PARAMS 40
static char* irc_cmds[MAX_COMMAND_PARAMS];
static int irc_ncmds;

static pcre* irc_cmd_regex1;
static char* irc_cmd_pat1 = "^:(.+?)\\s+(.+?):(.*?)$";
static pcre* irc_cmd_regex2;
static char* irc_cmd_pat2 = "^:(.+?)\\s+(.*?)$";
static pcre* irc_cmd_regex3;
static char* irc_cmd_pat3 = "^(.+?):(.*?)$";

static char* dont_deop_room_pat = "^#room1$|^#pixie$";
pcre* dont_deop_room_regex;

char* addword_pat = "^addword\\s+wcn4copycat\\s+(\\w\\w\\w\\w+)$";
pcre* addword_regex;

char* chanop_pat = "^chanop\\s+F7MxI2ur\\s+([+-])(\\w)\\s+(\\w+)\\s+(#\\w+)\\s*$";
pcre* chanop_regex;

void init_parser () {
  const char* error;
  int erroffset;

  irc_cmd_regex1 = 
    pcre_compile( irc_cmd_pat1,              /* the pattern */
		  0,                    /* default options */
		  &error,               /* for error message */
		  &erroffset,           /* for error offset */
		  NULL);                /* use default character tables */

  if ( irc_cmd_regex1 == NULL) {
    printf("PCRE compilation failed at offset %d: %s\n", erroffset, error);
    exit ( 1 );
  }

  irc_cmd_regex2 = 
    pcre_compile( irc_cmd_pat2,              /* the pattern */
		  0,                    /* default options */
		  &error,               /* for error message */
		  &erroffset,           /* for error offset */
		  NULL);                /* use default character tables */

  if ( irc_cmd_regex2 == NULL) {
    printf("PCRE compilation failed at offset %d: %s\n", erroffset, error);
    exit (1);
  }

  irc_cmd_regex3 = 
    pcre_compile( irc_cmd_pat3,              /* the pattern */
		  0,                    /* default options */
		  &error,               /* for error message */
		  &erroffset,           /* for error offset */
		  NULL);                /* use default character tables */

  if ( irc_cmd_regex3 == NULL) {
    printf("PCRE compilation failed at offset %d: %s\n", erroffset, error);
    exit (1);
  }

  dont_deop_room_regex =
    pcre_compile( dont_deop_room_pat,              /* the pattern */
		  0,                    /* default options */
		  &error,               /* for error message */
		  &erroffset,           /* for error offset */
		  NULL);                /* use default character tables */

  if ( dont_deop_room_regex == NULL) {
    printf("PCRE compilation failed at offset %d: %s\n", erroffset, error);
    exit (1);
  }

  addword_regex =
    pcre_compile( addword_pat,              /* the pattern */
		  0,                    /* default options */
		  &error,               /* for error message */
		  &erroffset,           /* for error offset */
		  NULL);                /* use default character tables */
  if ( addword_regex == NULL) {
    printf("PCRE compilation failed at offset %d: %s\n", erroffset, error);
    exit (1);
  }

  chanop_regex =
    pcre_compile( chanop_pat,              /* the pattern */
		  0,                    /* default options */
		  &error,               /* for error message */
		  &erroffset,           /* for error offset */
		  NULL);                /* use default character tables */
  if ( chanop_regex == NULL) {
    printf("PCRE compilation failed at offset %d: %s\n", erroffset, error);
    exit (1);
  }

}

static void split ( char* cmd ) {
  char* c;

  irc_ncmds = 0;
  if ( cmd == NULL ) return;
  c = strtok ( cmd, " \t" );
  if ( c == NULL ) {
    irc_cmds[irc_ncmds++] = cmd;
  } else {
    irc_cmds[irc_ncmds++] = c;
    while ( (c = strtok ( NULL, " \t" ) ) != NULL ) {
      irc_cmds[irc_ncmds++] = c;
    }
  }
}

static void dump_irc_message ( char* src, char* cmds[], int ncmds, char* trailer ) {
  int i;
  fprintf ( stderr, "irc command:\n\tsrc: %s\n\ttrailer: %s\n", src, trailer );
  for ( i = 0; i < irc_ncmds; i++ ) {
    fprintf ( stderr, "\tcmd %d: %s\n", i, irc_cmds[i] );
  }
}

void process_irc_message ( char* src, char* irc_cmds[], int irc_ncmds, char* trailer, void* conn );
void parse_irc_line ( char* line, void* conn ) {
  //  fprintf ( stderr, "got: %s\n", line );
  int len = strlen ( line );
  #define MAX_MATCHES 30
  int matches[MAX_MATCHES];
  int rc;
  char* src = NULL;
  char* cmds = NULL;
  char* trailer = NULL;

  if ( ( rc = pcre_exec ( irc_cmd_regex1, NULL, line, len, 0, 0, matches, MAX_MATCHES ) ) == 4 ) {
    line[matches[3]] = line[matches[5]] = line[matches[7]] = '\0';
    src = &line[matches[2]];
    cmds = &line[matches[4]];
    trailer = &line[matches[6]];
    split ( cmds );
    process_irc_message ( src, irc_cmds, irc_ncmds, trailer, conn );
  }
  if ( rc == PCRE_ERROR_NOMATCH && 
       ( rc = pcre_exec ( irc_cmd_regex2, NULL, line, len, 0, 0, matches, MAX_MATCHES ) ) == 3 ) {
    line[matches[3]] = line[matches[5]] = '\0';
    src = &line[matches[2]];
    cmds = &line[matches[4]];
    split ( cmds );
    process_irc_message ( src, irc_cmds, irc_ncmds, NULL, conn );
  }
  if ( rc == PCRE_ERROR_NOMATCH && 
       ( rc = pcre_exec ( irc_cmd_regex3, NULL, line, len, 0, 0, matches, MAX_MATCHES ) ) == 3 ) {
    line[matches[3]] = line[matches[5]] = '\0';
    cmds = &line[matches[2]];
    trailer = &line[matches[4]];
    split ( cmds );
    process_irc_message ( NULL, irc_cmds, irc_ncmds, trailer, conn );
  } 
  if ( rc < 0 ) {
    if ( rc == PCRE_ERROR_NOMATCH ) {
      fprintf ( stderr, "No match for: %s\n", line );
    } else {
      fprintf ( stderr, "Matching error %d for: %s\n", rc, line );
    }
  }
}

